// ============================================================================
// Name        : tp1-encode.s
// Authors     : Galli, Nadia
// 		 Pivetta, Agustin
// 		 Tkaczyszyn, Facundo
// Version     : 1.0
// Description : Tp1 66.20: Programacion MIPS
// ============================================================================
// Inicio del codigo
#include <mips/regdef.h>

.text
.align 2
// ============================================================================
// Esta funcion realiza el encoding a '1's y '0's y los vuelca a stdout
// size_t encode(char c)
// Diagrama de Stack
// 40 - [__a0__]_____________________
// 36 - [  pad ]
// 32 - [  ra  ] Saved Register Area
// 28 - [  fp  ]
// 24 - [  gp  ]_____________________
// 20 - [      ] Local and Temporary Area
// 16 - [      ]_____________________
// 12 - [      ] 
// 8  - [      ] Argument Building
// 4  - [      ] Area
// 0  - [      ]_____________________

.global encode
.ent encode

encode:
        .frame $fp,40,ra
	.set noreorder
	.cpload t9
	.set reorder
    
        // creo stack frame
        subu sp,sp,40   	#Reservo 40 Bytes (16 para parametros, 16 para respaldar los valores de fp, gp, ra, 8 para LTA)
        .cprestore 24

        sw ra,32(sp)		#Respaldo la posicion de la return address
        sw $fp,28(sp)		#Respaldo la posicion del frame pointer
	sw gp,24(sp)		#Respaldo la posicion del global pointer
	move $fp,sp
        sw a0,40($fp)		# guardo el argumento 0 en el ABA del caller

	// Inicializo registros
	li t0, 7		#t0 es i = 7, contador de loop
	move t1, a0		#t1 es el char que vamos a transformar a binario
	la t4, mascara_bits	
	sw t4, 20($fp)		#guardo el inicio del vector de mascaras en memoria

enc_for:
	bltz t0, encode_end	#Se termino el for
        lw t1,40($fp)		#cargo el char leido de memoria en t0
	sll t3, t0, 2		#genero la dir a acceder
	lw t4, 20($fp)		#cargo el inicio del vector de mascaras
	add t4,t4,t3
	lw t4, 0(t4)		#t4 va a servir para saber si hay 1 o 0 en el bit de la posicion i
	and t4, t1, t4		#Guardamos en t4 el resultado del AND entre el char y el bit de la posicion i
	
	sw t0, 16($fp)		#Guardo el index en memoria antes del syscall

	beqz t4, enc_is_zero	#Si es cero saltamos a enc_is_zero
	bnez t4, enc_not_zero	#Si no es cero saltamos a enc_not_zero

enc_is_zero:
	// Preparo para escribir 0 en el archivo
	li a0, 1		#Guardo 1 porque quiero escribir al stdout
	la a1, cero		#Le paso un cero
	li a2, 1		#Guardo 1 porque quiero escribir solo un byte
	b enc_write		#Salto para enc_write

enc_not_zero:
	// Preparo para escribir 1 en el archivo
	li a0, 1		#Guardo 1 porque quiero escribir al stdout
	la a1, uno		#Le paso un uno
	li a2, 1		#Guardo 1 porque quiero escribir solo un byte
	b enc_write		#Salto para enc_write

enc_write:
	jal write_asm		#Mando a escribir el 0 o el 1
	bne v1, zero, enc_error	#Verifica errores
	lw t0, 16($fp)		#cargo el index de memoria despues del syscall
	addi t0, t0, -1		#Decremento en 1 el contador
	b enc_for		#Loopea una vez mas

enc_error:
	li v0, -1 		#Muevo el codigo de error al retorno de la funcion y salgo de esta
	b encode_end

encode_end:
        lw ra,32($fp)		#Recupero la posicion del return address
	lw $fp,28($fp)		#Recupero la posicion del frame pointer
	lw gp,24($fp)		#Recupero la posicion del global pointer
	addu sp,sp,40
	j ra
	
.end encode

// ============================================================================
// Este programa genera un volcado de '1's y '0's de la informacion ingresada por stdin
// int main(int argc, char *argv[]);

// Diagrama de Stack
// 36 - [  a1  ]
// 32 - [__a0__]_____________________
// 28 - [  pad ]
// 24 - [  ra  ] Saved Register Area
// 20 - [  fp  ]
// 16 - [  gp  ]_____________________
// 12 - [      ] 
// 8  - [      ] Argument Building
// 4  - [      ] Area
// 0  - [      ]_____________________

.global main
.ent main

main:
        .frame $fp,32,ra
	.set noreorder
	.cpload t9
	.set reorder
    
        // creo stack frame
        subu sp,sp,32   	#Reservo 32 Bytes (16 para parametros, 16 para respaldar los valores de fp, gp, ra)
        .cprestore 16

        sw ra,24(sp)		#Respaldo la posicion de la return address
        sw $fp,20(sp)		#Respaldo la posicion del frame pointer
	sw gp,16(sp)		#Respaldo la posicion del global pointer
	move $fp,sp
        sw a0,32($fp)		# guardo el argumento 0 en el ABA del caller
        sw a0,36($fp)		# guardo el argumento 1 en el ABA del caller

	move v0, zero		#Inicializa en cero el retorno de la funcion

main_while:
	//leo de stdin
	li a0, 0		#Guardo 0 porque quiero leer del stdin
	la a1, rbuffer		#Paso el buffer de lectura
	li a2, 1		#Guardo 1 porque quiero leer solo un byte
	jal read_asm		
	bne v1,zero,main_error	#Verifica errores
	li t0, 1
	bne t0,v0,main_end	#Si no leyo 1 caracter, salgo
	
	lb t0,rbuffer(zero)	#Cargo el caracter leido
	move a0, t0		#Preparo el caracter leido como parámetro de encode
	jal encode
	li t0, -1
	beq v0,t0,main_end	#Sale del programa si hay error
	b main_while		#Loopea hasta que no haya nada mas que leer

main_error:
	li v0, 2 		#Muevo el codigo de error al retorno de la funcion y salgo de esta
	b main_end

main_end:
        lw ra,24(sp)		#Recupero la posicion del return address
	lw $fp,20(sp)		#Recupero la posicion del frame pointer
	lw gp,16(sp)		#Recupero la posicion del global pointer
	addu sp,sp,32
	j ra
.end main

// ============================================================================
// Datos
.data
.align 2

// Buffer de lectura
rbuffer:	.byte 0

// Mascara para sacar los bits de un byte
mascara_bits:	.word 1,2,4,8,16,32,64,128

// Constantes para guardar en el archivo
cero:		.ascii "0" #Declaro el cero
uno:		.ascii "1" #Declaro el uno
